/* eslint-disable vue/prop-name-casing */
import type { VNode } from 'vue'
import type { LoadingInstance } from 'element-plus/es/components/loading/src/loading'
import type {
  ColumnsSettingType,
  ProSaasTablePropsType,
  ProSaasTableStateType,
  PaginationType,
  TableColumnProps,
  TableColumnRenderRowPropsType
} from './typings'
import {
  defineComponent,
  ref,
  reactive,
  onMounted,
  watch,
  watchSyncEffect,
  computed,
  isRef
} from 'vue'
import { useStore } from 'vuex'
import { get } from 'lodash'
import {
  ElRow,
  ElCol,
  ElTable,
  ElTableColumn,
  ElPagination,
  ElSpace,
  ElLink,
  ElLoading
} from 'element-plus'
import AliIcon from '~/components/AliIocn'
import ColumnsTypeDrawer from './columnsTypeDrawer'
import SearchForm from '~/components/ProForm/SearchForm'
import formatterData from '~/utils/formatter'
// import { transHump } from '~/utils/util'
import styles from './index.module.scss'

/**
 * search功能待完善  可用api可参考根目录的 readme.md
 * props参考typeings里的ProSaasTablePropsType传参 参数要附带data子项类型
 */
const ProSaasTable: <T>(props: ProSaasTablePropsType<T>) => VNode = defineComponent({
  name: 'ProSaasTable',
  props: [
    'width',
    'height',
    'maxHeight',
    'stripe',
    'rowKey',
    'showHeader',
    'rowClassName',
    'showSummary',
    'sumText',
    'rowStyle',
    'cellClassName',
    'cellStyle',
    'headerRowClassName',
    'headerRowStyle',
    'headerCellClassName',
    'headerCellStyle',
    'highlightCurrentRow',
    'currentRowKey',
    'emptyText',
    'expandRowKeys',
    'defaultSort',
    'defaultExpandAll',
    'tooltipEffect',
    'spanMethod',
    'selectOnIndeterminate',
    'indent',
    'treeProps',
    'lazy',
    'className',
    'sort',
    'clearSelection',
    'getSelectionRows',
    'toggleRowSelection',
    'toggleAllSelection',
    'toggleRowExpansion',
    'setCurrentRow',
    'clearSort',
    'clearFilter',
    'doLayout',
    'scrollTo',
    'setScrollTop',
    'setScrollLeft',
    'fit',
    'size',
    'border',
    'data',
    'columns',
    'searchFormProps',
    'searchformResponsiveCol',
    'useGridLayout',
    'dispatchType',
    'dispatchTypeGetListKeys',
    'dispatchTypeGetTotalKeys',
    'needPagination',
    'paginationProps',
    'hasIndex',
    'searchParams',
    'headerTitle',
    'expand',
    'hasSelection',
    'rowClickSelection',
    'onSelect',
    'onExpand-change',
    'onCurrent-change',
    'onSelect-all',
    'onSelection-change',
    'onCell-mouse-enter',
    'onCell-mouse-leave',
    'onCell-contextmenu',
    'onCell-click',
    'onCell-dblclick',
    'onRow-click',
    'onRow-contextmenu',
    'onRow-dblclick',
    'onHeader-click',
    'onHeader-contextmenu',
    'onSort-change',
    'onFilter-change',
    'onHeader-dragend',
    'loading',
    'tableId', // 这里的tableId是需要拼接userId才能用的 否则不会根据账号区分
    'filterTableDataMethod',
    'noInitSearch'
  ],
  setup(props: ProSaasTablePropsType<any>, { slots, expose }) {
    const loadRef = ref<LoadingInstance>()
    const elTableRef = ref()
    const searchFormRef = ref()
    const drawerRef = ref<TableColumnProps<any>[]>([])
    const state = reactive<ProSaasTableStateType>({
      data: [],
      pagination: {
        currentPage: 1,
        pageSize: 15,
        pageSizes: [15, 20, 30, 40, 50, 100],
        total: 0,
        background: true,
        small: false,
        layout: 'total, sizes, prev, pager, next, jumper'
      },
      selecteds: [],
      visible: false,
      searchLoading: false,
      sortParams: {}
    })
    const store = useStore()

    // 切换table列配置展示和隐藏
    const handleChangeDrawerVisible = () => {
      state.visible = !state.visible
    }

    // 内置搜索函数
    const handleSearchList = async () => {
      const {
        dispatchType,
        needPagination = true,
        searchParams,
        searchFormProps,
        dispatchTypeGetListKeys = 'data.records',
        dispatchTypeGetTotalKeys = 'data.total',
        filterTableDataMethod
      } = props
      if (!dispatchType) return
      state.searchLoading = true
      const res = await store.dispatch(
        dispatchType,
        needPagination
          ? Object.assign(
              {
                current: state.pagination.currentPage,
                size: state.pagination.pageSize,
                ...(searchFormProps?.model || {})
              },
              searchParams || {},
              state.sortParams?.sortType && state.sortParams?.sortKey
                ? {
                    [state.sortParams?.sortType]: state.sortParams?.sortKey
                  }
                : {}
            )
          : searchParams || {}
      )
      state.searchLoading = false
      state.data = filterTableDataMethod
        ? filterTableDataMethod(get(res, dispatchTypeGetListKeys) || [])
        : get(res, dispatchTypeGetListKeys) || []
      state.pagination.total = get(res, dispatchTypeGetTotalKeys)
    }

    /**
     * 内置分页函数 注：内置函数只会改变内置的state的值
     * @param key state里的pagination或者paginationProps中的key
     * @param value 要改变key对应的值
     */
    const handleChangePaintaion = async (key: keyof PaginationType, value: string) => {
      if (state?.pagination?.[key]) (state.pagination[key] as any) = value
      await handleSearchList()
    }

    // 切换复选框回调
    const handleChangeSelectionCheckbox = (selecteds: []) => {
      state.selecteds = selecteds
    }

    //  点击行选择复选框
    const handleRowClick = (row: any) => {
      const ids = state.selecteds?.map((item) => item.id)
      if (ids.indexOf(row.id) === -1) {
        elTableRef.value.toggleRowSelection(row, true)
      } else {
        elTableRef.value.toggleRowSelection(row, false)
      }
    }

    // 切换排序回调
    const handleChangeSortKey: ProSaasTablePropsType<any>['onSort-change'] = (sortProp) => {
      // 升序降序类型和字段后并查询
      state.sortParams!.sortType = sortProp.order === 'ascending' ? 'ascs' : 'descs'
      // state.sortParams!.sortKey = sortProp.prop && transHump(sortProp.prop)
      state.sortParams!.sortKey = sortProp.prop
      if (!props.noInitSearch) handleSearchList()
    }

    // columnRender处理函数
    const handleColumnRender = (
      rowProps: TableColumnRenderRowPropsType<any>,
      item: TableColumnProps<any>
    ): VNode => {
      const itemValue = rowProps?.row?.[rowProps?.column?.property!]
      // 如果需要值过滤则过滤将过滤后的值返回出来
      if (item?.valueType) {
        return item?.render ? (
          item?.render!(rowProps, formatterData?.[item?.valueType]?.(itemValue) ?? itemValue)
        ) : (
          <>{formatterData?.[item?.valueType]?.(itemValue) ?? itemValue}</>
        )
      }
      // 如果需要枚举的对象存在则枚举出值 如果没有值 则返回itemValue
      if (item?.enumValues) {
        const enumFilterValue =
          item.enumValues && isRef(item.enumValues)
            ? (item?.enumValues?.value as Record<string, any>)[itemValue]
            : item?.enumValues[itemValue]
        return item?.render ? (
          item?.render!(rowProps, enumFilterValue || itemValue)
        ) : (
          <>{enumFilterValue || itemValue}</>
        )
      }
      return item?.render ? item?.render!(rowProps, itemValue) : <>{itemValue}</>
    }

    // 切换设置表头的回调函数
    const handleChangeSettingColumns = (columnsSetting: ColumnsSettingType) => {
      const { tableId } = props
      drawerRef.value = props.columns
        ?.filter((item) => (item.prop in columnsSetting ? columnsSetting[item.prop].show : false))
        .sort((prev, next) => columnsSetting[prev.prop]?.sort - columnsSetting[next.prop]?.sort)
      if (tableId) localStorage.setItem(state.tableId!, JSON.stringify(columnsSetting))
    }

    // 监听columns变化就更新columns
    watchSyncEffect(() => {
      drawerRef.value = props.columns
    })
    // watch(props.columns, () => {
    //   drawerRef.value = props.columns
    // })

    watch(
      () => state.searchLoading || props.loading,
      () => {
        if (state.searchLoading || props.loading) {
          loadRef.value = ElLoading.service({
            target: '.el-table'
          })
        } else {
          loadRef.value!?.close?.()
        }
      }
    )

    // 监听pagination需要双向数据绑定的currentPage和pageSize变化触发更新
    if (props.paginationProps) {
      if (props.paginationProps.currentPage) {
        watchSyncEffect(() => {
          state.pagination.currentPage = (props.paginationProps as PaginationType).currentPage
        })
      }
      if (props.paginationProps.pageSize) {
        watchSyncEffect(() => {
          state.pagination.pageSize = (props.paginationProps as PaginationType).pageSize
        })
      }
    }

    onMounted(() => {
      const { tableId, defaultSort, noInitSearch } = props
      // 如果有tableId则设置
      if (tableId) state.tableId = `${tableId}${store.getters['user/userInfo']?.userId}`
      const localColumnsSetting: ColumnsSettingType =
        tableId && JSON.parse(localStorage.getItem(state.tableId!) as string)
      if (localColumnsSetting) {
        drawerRef.value = props.columns
          ?.filter((item) =>
            item.prop in localColumnsSetting ? localColumnsSetting[item.prop].show : false
          )
          .sort(
            (prev, next) =>
              localColumnsSetting[prev.prop]?.sort - localColumnsSetting[next.prop]?.sort
          )
      } else {
        drawerRef.value = props.columns?.filter((item) => !item?.hidden)
      }
      if (defaultSort) {
        handleChangeSortKey(defaultSort)
        return
      }
      if (!noInitSearch) handleSearchList()
    })

    // 暴露方法给父组建
    expose({
      filterColumns: computed(() => drawerRef.value),
      elTableRef: computed(() => elTableRef.value),
      searchFormRef: computed(() => searchFormRef?.value?.searchFormRef),
      pagination: computed(() => state.pagination),
      selecteds: computed(() => state.selecteds),
      toSearch: handleSearchList
    })
    return () => {
      const {
        searchFormProps = {},
        searchformResponsiveCol = [],
        useGridLayout = true,
        dispatchType,
        needPagination = true,
        paginationProps = null,
        hasIndex = false,
        hasSelection = false,
        rowClickSelection = false,
        headerTitle,
        expand
      } = props
      return (
        <>
          {searchformResponsiveCol?.length > 0 && (
            <SearchForm
              ref={searchFormRef}
              searchFormProps={searchFormProps}
              searchformResponsiveCol={searchformResponsiveCol}
              useGridLayout={useGridLayout}
              handleSearchList={handleSearchList}
              loading={state.searchLoading}
            />
          )}
          {slots.default && (
            <section class={styles['pro-saas-table-default-slot']}>{slots.default()}</section>
          )}
          {headerTitle && (
            <section class={styles['pro-saas-table-header']}>
              <section class={styles['pro-saas-table-header-title']}>{headerTitle}</section>
              {dispatchType && (
                <section class={styles['pro-saas-table-header-tools']}>
                  <ElSpace>
                    <ElLink type="primary" underline={false} onClick={handleSearchList}>
                      <AliIcon type="icon-zhongzhi" />
                    </ElLink>
                    <ElLink type="primary" underline={false} onClick={handleChangeDrawerVisible}>
                      <AliIcon type="icon-shezhi" />
                    </ElLink>
                  </ElSpace>
                </section>
              )}
            </section>
          )}
          <ElTable
            onSort-change={handleChangeSortKey}
            {...(props as any)}
            size={props.size}
            border={props.border !== false}
            {...(hasSelection
              ? {
                  'onSelection-change':
                    props?.['onSelection-change'] || handleChangeSelectionCheckbox
                }
              : {})}
            {...(rowClickSelection
              ? {
                  'onRow-click': props?.['onRow-click'] || handleRowClick
                }
              : {})}
            ref={elTableRef}
            data={props.data ? props.data : state.data}
            v-slots={{
              append: slots?.append,
              empty: slots?.empty
            }}
          >
            {hasSelection && (
              <ElTableColumn type="selection" width="46px" label="#" align="center" />
            )}
            {expand && (
              <ElTableColumn
                type="expand"
                v-slots={{
                  default: (scope: any) => {
                    return <>{expand(scope.row.detailVOList || [])}</>
                  }
                }}
              />
            )}
            {hasIndex && (
              <ElTableColumn
                type="index"
                label="#"
                width="90px"
                align="center"
                headerAlign="center"
              />
            )}
            {drawerRef.value?.map((item, index) => (
              <ElTableColumn
                key={index + (item.prop as string)}
                {...(item as any)}
                fixed={item?.unFixed || !item?.fixed ? false : item?.fixed}
              >
                {{
                  default:
                    item?.render || item?.enumValues || item?.valueType
                      ? (rowProps: TableColumnRenderRowPropsType<any>) =>
                          handleColumnRender(rowProps, item)
                      : undefined,
                  header: item?.fixed
                    ? () => (
                        <>
                          {item.label}
                          &emsp;
                          <ElLink
                            type="primary"
                            underline={false}
                            onClick={(e: Event) => {
                              e.stopPropagation()
                              drawerRef.value[index].unFixed = !item.unFixed
                              drawerRef.value = [...drawerRef.value]
                            }}
                          >
                            <AliIcon
                              class={{ [styles['pro-saas-table-fixed-icon']]: item.unFixed }}
                              type={
                                item.unFixed
                                  ? 'icon-gudinglieweixuanzhong'
                                  : 'icon-gudingliexuanzhong'
                              }
                            />
                          </ElLink>
                        </>
                      )
                    : undefined
                }}
              </ElTableColumn>
            ))}
          </ElTable>
          {needPagination && (
            <ElRow class="pro-saas-table-pagination-box">
              <ElCol class={styles['pro-saas-table-pagination']}>
                <ElPagination
                  v-model:currentPage={state.pagination.currentPage}
                  v-model:pageSize={state.pagination.pageSize}
                  {...Object.assign(state.pagination, paginationProps || {})}
                  onSize-change={
                    paginationProps?.['onSize-change'] ||
                    ((pageSize: number) => handleChangePaintaion('pageSize', pageSize as any))
                  }
                  onCurrent-change={
                    paginationProps?.['onCurrent-change'] ||
                    ((currentPage: number) =>
                      handleChangePaintaion('currentPage', currentPage as any))
                  }
                />
              </ElCol>
            </ElRow>
          )}
          {state.visible && (
            <ColumnsTypeDrawer
              tableId={state.tableId}
              visible={state.visible}
              columns={props.columns}
              filterColumns={drawerRef.value}
              onChangeSettingColumns={handleChangeSettingColumns}
              onClose={handleChangeDrawerVisible}
            />
          )}
        </>
      )
    }
  }
}) as any

export default ProSaasTable
